from django_redis import get_redis_connection
from redis.client import StrictRedis
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from rest_framework.serializers import Serializer

# 校验等核心操作都封装在序列化器中
from oauth.models import OAuthQQUser
from oauth.utils import check_encrypted_openid
from users.models import User


class QQUserSerializer(Serializer):
    # 因4个参数无关联属性没有模型类所以手动添加实现校验

    ''' 绑定openid和美多用户的序列化器
        作用是校验4个简单的请求参数 ，没有用到序列化功能

     #二、序列化器（绑定逻辑实现）
        # 1. 获取请求参数: mobile, password, sms_code, openid
        # 2. 校验openid是否合法
        # 3. 校验短信验证码是否正确
        # 4. 判断要绑定的用户是否存在
        # 	- 用户不存在，则以手机号作为用户名，创建美多用户
        # 	- 用户存在，判断密码是否正确
        # 5. 绑定openid和美多用户（往映射表添加一条数据）
        #   create() : 绑定逻辑实现
    '''

    # 首先定义这些校验方法 参数 write_only=True 用于校验 没有用到序列化器所以为true
    openid = serializers.CharField(label='openid', write_only=True)
    mobile = serializers.RegexField(label='手机号', regex=r'^1[3-9]\d{9}$', write_only=True)  # RegexField 使用正则校验
    password = serializers.CharField(label='密码', max_length=20, min_length=4, write_only=True)
    sms_code = serializers.CharField(label='短信验证码', write_only=True)

    # ctrl + o 重写validate方法 里面全是校验的操作
    def validate(self, attrs):
        # attrs 就是data=request.data 他的值 可以对attr进行增删改查 所以返回的 attr 不一定等于 data

        # 1. 获取请求参数: mobile, password, sms_code, openid
        mobile = attrs.get('mobile')
        password = attrs.get('password')
        sms_code = attrs.get('sms_code')
        openid = attrs.get('openid')



        # 2. 校验openid是否合法 # 后面加密后在校验
        openid = check_encrypted_openid(openid)  # 结果: 明文的字符串
        if openid is None:
            raise ValidationError({'message': 'openid不合法'})

        # # 修改字典中的Openid为明文的openid
        attrs['openid'] = openid

        # 3. 校验短信验证码是否正确
        # todo 校验短信验证码

        # 1.从数据库中获取正确的短信验证码
        strict_redis = get_redis_connection('sms_codes')  # type:StrictRedis
        real_sms_code = strict_redis.get('sms_%s' % mobile)
        if not real_sms_code:
            raise ValidationError(' 短信验证码无效')

        # 3. 比较是否相等
        if real_sms_code.decode() != sms_code:
            raise ValidationError({'message':'短信验证码不正确'})

        # 4. 判断要绑定的用户是否存在
        # 首先要通过手机号判断用户存不存在
        try:
            user = User.objects.get(mobile=mobile)  # 获取绑定的美多用户

        except User.DoesNotExist:
            # - 用户不存在，则以手机号作为用户名，创建美多用户
            user = User.objects.create_user(username=mobile, password=password, mobile=mobile)

        else:  # - 用户存在，判断密码是否正确 正确返回true
            if not user.check_password(password):
                raise ValidationError({'message':'要绑定用户的密码不正确'})

        # 往字典中新增一个用户 以便后续绑定openid时使用 提前添加
        attrs['user'] = user
        return attrs  # 要校验通过的数据要返回去

    # 绑定操作 重写 create 方法 绑定逻辑
    def create(self, validated_data):
        user = validated_data.get('user')
        # 5. 绑定openid和美多用户（往映射表添加一条数据）oauth/models.py 里面添加一条数据
        #   create() : 绑定逻辑实现 return attrs 返回attr  create() 接收 attr
        # qquser 为一条映射数据 返回的是user这个用户
        qquser = OAuthQQUser.objects.create(openid=validated_data.get('openid'), user=user)

        return user  # 返回绑定的美多对象


